#ifndef __OBJECT_H_
#define __OBJECT_H_
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <set>
#include "Global.h"
#include <ctime>
// #include "shop.h"
extern std::string global_username;
extern std::string global_digit;
#define DEFINE_SET_GET(name,type) type Get##name()const{return name;}\
    void Set##name(const type& name){this->name = name;}
class Point
{

public:
    Point():X(0),Y(0){}
    Point(int X,int Y):X(X),Y(Y){}
    DEFINE_SET_GET(X,int);
    DEFINE_SET_GET(Y,int);
public:
    int X;
    int Y;
};
//抽象对象:
class VirtualObject:public Point
{
public:
    VirtualObject():Point(),HP(0),Attack(0),defends(0){}
    VirtualObject(int x,int y,const std::string& Name,const std::string& Symbol,int HP = 0,int Attack = 0,int defends = 0,int Exp = 0):Point(x,y),Name(Name),Symbol(Symbol),HP(HP),Attack(Attack),defends(defends),Exp(Exp){}
    DEFINE_SET_GET(HP,int)
    DEFINE_SET_GET(Attack,int)
    DEFINE_SET_GET(defends,int)
    DEFINE_SET_GET(Name,std::string)
    DEFINE_SET_GET(Symbol,std::string)
    DEFINE_SET_GET(Exp,int);
    int GetX() const { return X; }
    int GetY() const { return Y; }
public:
    std::string Name;
    std::string Symbol;
    int HP;
    int Attack;
    int defends;
    int Exp;

};

class TreasureBox;
class Monster;
class Scene;
class Prop;
class Bag;
using PropPtr =  std::shared_ptr<Prop>;
class Player:public VirtualObject
{
public:
    // Player() : VirtualObject(), money(0), Level(1), b(std::make_unique<Bag>()) {}
    Player():VirtualObject(){}
    Player(int x,int y,const std::string&name,const std::string& Symbol,int HP,int Attack,int defends);
    // ~Player();
    DEFINE_SET_GET(money,int);
    DEFINE_SET_GET(Level,int);
    
    Bag& GetBag(){return *b;}
    // Scene& GetScene(){return *scene;}
    void Move();
    void show();
    void HandleGameFlow();
    void LevelUp();

    void SavePlayerAttributesToFile();
    void LoadPlayerAttributesFromFile();
    bool exist();
    // void setscence()
    void InitMonsters();
    void saveMonsters();
    std::vector<std::shared_ptr<Monster>> loadMonsters();
    bool Exits();
    void MonsterShow();
    void RefreshMonster(Monster *m);
    std::vector<std::shared_ptr<Monster>>& GetMonster()
    {
        return monsters;
    }
    
    void deleteFile();
public:
    int money;
    int Level;
    // Bag *b;
    std::unique_ptr<Bag> b;
    std::vector<std::shared_ptr<Monster>> monsters;
    std::pair<int, int> generateUniqueCoordinates();
    std::set<std::pair<int, int>> usedCoordinates;
    std::string Map[MapSize][MapSize];
    // Monster *m;
    std::shared_ptr<TreasureBox> Box;
    std::vector<std::shared_ptr<TreasureBox>> treasureBoxes;
};

class Monster:public VirtualObject
{
public:
    Monster():VirtualObject(){}
    Monster(int x,int y,const std::string&name,const std::string& Symbol,int HP,int Attack,int defends,int Exp,int money);
    void show();
    DEFINE_SET_GET(MaxHp,int);
    DEFINE_SET_GET(Money,int);
private:
    int MaxHp;
    int Exp;
    int Money;
};

class Prop
{
public:
    Prop(int money,const std::string& name,int number): money_(money), name_(name),number_(number) {}
    DEFINE_SET_GET(money_,int);
    DEFINE_SET_GET(name_,std::string);
    DEFINE_SET_GET(number_,int);
    virtual void show() const 
    {
        std::cout << "序号: " << number_ << " 名字: " << name_ << " 金额: " << money_ << " ";
    }
    virtual int GetAttack() const { return 0; }
    virtual int GetDefends() const { return 0; }
    virtual int GetHP() const { return 0; }
    virtual ~Prop() {}  // 将析构函数声明为虚函数
private:
    int money_;
    std::string name_;
    int number_;
};

class Weapon:public Prop
{
public:
    Weapon(int money, const std::string& name,int number, int attack):Prop(money, name,number),Attack(attack){}
    void show() const override 
    {
        Prop::show();
        std::cout << "攻击力: " << Attack << std::endl;
    }
    DEFINE_SET_GET(Attack,int);
    // int GetAttack() const override { return Attack; }
private:
    int Attack;
};

class Defencer:public Prop
{
public:
    Defencer(int money, const std::string& name, int number,int defends) : Prop(money, name,number), Defends(defends) {}
    void show() const override 
    {
        Prop::show();
        std::cout << "防御力: " << Defends << std::endl;
    }
    DEFINE_SET_GET(Defends,int);
    // int GetDefence() const override { return Defends; }
private:
    int Defends;
};

class Medicine:public Prop
{
public:
    Medicine(int money, const std::string& name,int number, int hp) : Prop(money, name,number), HP(hp) {}
    void show() const override 
    {
        Prop::show();
        std::cout << "HP: " << HP << std::endl;
    }
    DEFINE_SET_GET(HP,int);
    // int GetHP() const override { return HP; }
private:
    int HP;   
};



class PropFactory
{
public:
    virtual ~PropFactory() = default;
    virtual std::shared_ptr<Prop> createProp(int money, const std::string& name, int number, int attribute) const = 0;
};

class WeaponFactory : public PropFactory
{
public:
    std::shared_ptr<Prop> createProp(int money, const std::string& name, int number, int attack) const override
    {
        return std::make_shared <Weapon>(money, name, number, attack);
    }
};

class DefencerFactory : public PropFactory
{
public:
    std::shared_ptr<Prop> createProp(int money, const std::string& name, int number, int defends) const override
    {
        return std::make_shared <Defencer>(money, name, number, defends);
    }
};

class MedicineFactory : public PropFactory
{
public:
    std::shared_ptr<Prop> createProp(int money, const std::string& name, int number, int hp) const override
    {
        return std::make_shared <Medicine>(money, name, number, hp);
    }
};



class Bag
{
public:
    Bag(Player& player) : p(player) {}
    Bag() = default; // 默认构造函数
    //插入
    void Insert(const PropPtr &p);
    //装备
    void Equip(size_t index);
    //取出
    void Unequip(size_t index);
    //丢弃
    void Remove(size_t index);
    void RemoveL();
    void ShowEquippedItems();
    void show();
    std::string GetName()
    {
        auto ite = props.back();
        return ite->Getname_();
    }
    void SaveToFile();
    void LoadFromFile();
public:
    std::vector<PropPtr> props;
    std::vector<PropPtr> equippedItems; 
    Player &p;
    int nextNumber_ = 1;
};

class Scene;
class Player;
class TreasureBox : public VirtualObject
{
public:
    TreasureBox(Player& p): p(p){}
    TreasureBox(int x, int y, const std::string& name, const std::string& symbol, Player& player): VirtualObject(x, y, name, symbol), p(player){}

    void Generate()
    {
         // 初始化一些物品
        items.push_back(std::make_shared<Weapon>(100, "Sword", 0, 15));
        items.push_back(std::make_shared<Weapon>(150, "Axe", 0, 20));
        items.push_back(std::make_shared<Defencer>(80, "Shield", 0, 10));
        items.push_back(std::make_shared<Medicine>(50, "Health Potion", 0, 25));
    }

    const std::vector<PropPtr>& getItems() const { return items; }
     // 删除特定索引的商品
    void deleteItemAtIndex(size_t index) 
    {
        if (index < items.size())
        {
            items.erase(items.begin() + index);
        }
    }


    void Get()
    {  
        AddRandomItem();
        RemoveFromScene();
    }
    void AddRandomItem()
    {   
        // 添加这一行来设置随机种子
        std::srand(std::time(nullptr));
        int randomType = std::rand() % 4;
        if (randomType == 0) // 生成钱
        {   
            int t = GenerateRandomMoney();
            p.GetBag().Insert(std::make_shared<Prop>(t, "Money", nextNumber_++));
            p.Setmoney(p.Getmoney() + t);
        }
        else // 生成随机物品
        {   
            for(int i = 0;i < 100;i++)
            {
                if(p.GetBag().props.size() == i)
                {
                    nextNumber_ = i + 1;
                }
            }
            // 生成随机索引
            int randomIndex = std::rand() % p.Box->getItems().size();
            p.GetBag().Insert(p.Box->getItems()[randomIndex]);
            p.Box->deleteItemAtIndex(randomIndex);
        }
    }
    void RemoveFromScene();

    void InitTreasureBoxes();
    bool isOverlap(std::vector<std::shared_ptr<TreasureBox>> &treasureBoxes, int x, int y);
    void RemoveTreasureBox(int index);
    int GetTreasureBoxIndex(TreasureBox* t);
    std::vector<std::shared_ptr<TreasureBox>>& GetTrea()
    {
        return treasureBoxes;
    }

    void saveTreasureBoxes();
    void loadTreasureBoxes(std::vector<std::shared_ptr<TreasureBox>>& treasureBoxes);
    bool ExistTreasureBoxes();
private:
    int GenerateRandomMoney() const { return std::rand() % 100 + 1; }
    std::vector<std::shared_ptr<TreasureBox>> treasureBoxes;
    // Shop &s;
    Player& p;
    // Scene& sc;
    int nextNumber_ = 1;
    std::vector<PropPtr> items;
};

#endif